package com.it.App.config;

import com.it.App.exception.AccessDeniedHandlerImpl;
import com.it.App.exception.AuthenticationEntryPointImpl;
import com.it.App.filter.JWTAuthenticationFilter;
import io.swagger.models.HttpMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @Author: CaoYouGen
 * @DateTime: 2023/11/22/10:29
 * @注释: TODO
 **/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用全局方法安全
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    public static final String[] URL_WHITELIST = {
            "/favicon.ico",

            "/sys/captcha",
            "/sys/login",
            "/sys/logout",
            "/swagger-resources/**",
            "/v2/api-docs",
            "/swagger-ui.html",
            "/webjars/**", // 放行knife4j生成的接口文档(/swagger-resources 和 /v2/api-docs 还有一些其他的资源路径， /swagger-ui.html、/webjars/** )
    };

    @Autowired
    private JWTAuthenticationFilter jwtAuthenticationFilter;

    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;

    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    // 指定一个密码的加密方式
    @Bean
    BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    // 配置HttpSecurity，定义安全策略
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .csrf().disable() // 启用跨越支持，禁用CSRF保护
                .formLogin()

                .and()
                .authorizeRequests()
                .antMatchers(URL_WHITELIST).permitAll() // 设置白名单，允许访问的URL
                .antMatchers(String.valueOf(HttpMethod.OPTIONS), "/**").permitAll() // 放行OPTIONS请求： Swagger可能会发出OPTIONS请求，确保这个请求也被放行
                .antMatchers("/user/save").hasAuthority("sys:role:save") // 访问 /user/save接口 必须要拥有sys:role:save权限
                .anyRequest().authenticated()  // 其他所有请求需要身份验证

                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 不会创建session

        // 将登录验证码校验过滤器加入到过滤器链中
        http.addFilterBefore(jwtAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);

        // 配置异常处理器（认证异常和授权异常）
        http.exceptionHandling()
                // 配置 认证异常处理器
                .authenticationEntryPoint(authenticationEntryPoint)
                // 配置授权异常处理器
                .accessDeniedHandler(accessDeniedHandler);
    }
}
